package com.siyu.predict.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.siyu.basedata.modelparam.domain.ModelParam;
import com.siyu.basedata.modelparam.service.IModelParamService;
import com.siyu.basedata.plan.domain.Plan;
import com.siyu.basedata.plan.service.IPlanService;
import com.siyu.basedata.pptnrlaste.domain.PptnRLaste;
import com.siyu.basedata.pptnrlaste.service.IPptnRLasteService;
import com.siyu.basedata.pptnrsence.domain.PptnRSence;
import com.siyu.basedata.pptnrsence.service.IPptnRSenceService;
import com.siyu.basedata.rainsence.domain.RainSence;
import com.siyu.basedata.rainsence.service.IRainSenceService;
import com.siyu.basedata.rsvrrlaste.domain.RsvrRLaste;
import com.siyu.basedata.rsvrrlaste.service.IRsvrRLasteService;
import com.siyu.basedata.wrprsrbsin.domain.WrpRsrBsin;
import com.siyu.basedata.wrprsrbsin.service.IWrpRsrBsinService;
import com.siyu.basedata.wrprsrhych.domain.WrpRsrHych;
import com.siyu.basedata.wrprsrhych.service.IWrpRsrHychService;
import com.siyu.basedata.xajresult.domain.XajResult;
import com.siyu.basedata.xajresult.service.IXajResultService;
import com.siyu.common.core.controller.BaseController;
import com.siyu.common.core.domain.AjaxResult;
import com.siyu.common.core.page.TableDataInfo;
import com.siyu.common.utils.StringUtils;
import com.siyu.common.utils.WordReport;
import com.siyu.common.utils.uuid.IdUtils;
import com.siyu.model.dispatch.dto.DispatchDto;
import com.siyu.model.dispatch.io.FloodDispatchOutput;
import com.siyu.model.dispatch.io.SingleDamInput;
import com.siyu.model.dispatch.model.DispatchModel;
import com.siyu.predict.dto.*;
import com.siyu.predict.rsvrjob.domain.RsvrJob;
import com.siyu.predict.rsvrjob.service.IRsvrJobService;
import com.siyu.predict.service.PredictService;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.siyu.model.dispatch.utils.ParamMakeUtils.paramMakeUtils;

@RestController
@RequestMapping("/predict")
public class PredictController extends BaseController {
    @Autowired
    private PredictService predictService;
    @Autowired
    private IModelParamService modelParamService;
    @Autowired
    private IPlanService planService;
    @Autowired
    private IPptnRLasteService pptnRLasteService;
    @Autowired
    private IRsvrRLasteService rsvrRLasteService;
    @Autowired
    private IWrpRsrHychService wrpRsrHychService;
    @Autowired
    private IXajResultService xajResultService;
    @Autowired
    private IRainSenceService rainSenceService;
    @Autowired
    private IPptnRSenceService pptnRSenceService;
    @Autowired
    private IRsvrJobService rsvrJobService;
    @Autowired
    private IWrpRsrBsinService wrpRsrBsinService;


    /**
     * 获取水库特征值
     */
    @GetMapping("/model/rsvrtrait")
    public AjaxResult getRsvrtrait(String rscd) {
        try {
            WrpRsrHych one = wrpRsrHychService.lambdaQuery().eq(WrpRsrHych::getRscd, rscd).one();
            return AjaxResult.success(one);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 假拟计算
     */
    @PostMapping("/model/hypcalc")
    public AjaxResult hypCalc(@RequestBody HypCalcDto hypCalcDto) {
        try {
            Map<Object, Object> map = predictService.hypCalc(hypCalcDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 实时计算
     */
    @PostMapping("/model/relcalc")
    public AjaxResult relCalc(@RequestBody RelCalcDto relCalcDto) {
        try {
            Map<Object, Object> map = predictService.relCalc(relCalcDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 历史计算
     */
    @PostMapping("/model/hiscalc")
    public AjaxResult hisCalc(@RequestBody HisCalcDto hisCalcDto) {
        try {
            Map<Object, Object> map = predictService.hisCalc(hisCalcDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 面雨量实测数据查询
     */
    @GetMapping("/drp/list")
    public AjaxResult drpList(PlanDto planDto) {
        try {
            Map<Object, Object> map = predictService.getDrpData(planDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 面雨量实时预报数据查询
     */
    @GetMapping("/predrp/prelist")
    public AjaxResult predrpList(PlanDto planDto) {
        try {
            Map<Object, Object> map = predictService.getpreDrpData(planDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 预报方案列表查询
     */
    @GetMapping("/plan/list")
    public TableDataInfo planList(PlanDto planDto) {
        startPage();
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.select("id", "create_by", "plan_name", "step", "create_time", "plan_desc", "plan_type")
                .like(BeanUtil.isNotEmpty(planDto.getPlanName()), "plan_name", planDto.getPlanName())
                .eq(BeanUtil.isNotEmpty(planDto.getPlanType()), "plan_type", planDto.getPlanType())
                .eq(BeanUtil.isNotEmpty(planDto.getCalcType()), "calc_type", planDto.getCalcType())
                .eq(BeanUtil.isNotEmpty(planDto.getStartTime()), "start_time", planDto.getStartTime())
                .eq(BeanUtil.isNotEmpty(planDto.getEndTime()), "end_time", planDto.getEndTime())
                .ge(BeanUtil.isNotEmpty(planDto.getCreateStartTime()), "create_time", planDto.getCreateStartTime())
                .le(BeanUtil.isNotEmpty(planDto.getCreateEndTime()), "create_time", planDto.getCreateEndTime())
                .eq(BeanUtil.isNotEmpty(planDto.getRscd()), "rscd", planDto.getRscd())
                .orderByDesc("create_time")
                .eq("pre_type", "预报");
        return getDataTable(planService.list(planQueryWrapper));
    }

    /**
     * 预报方案列表查询
     */
    @GetMapping("/plan/listall")
    public AjaxResult planallList(PlanDto planDto) {
        QueryWrapper<Plan> planQueryWrapper = new QueryWrapper<>();
        planQueryWrapper.select("id", "plan_name", "plan_type")
                .eq("rscd", planDto.getRscd())
                .orderByDesc("end_time")
                .eq("pre_type", "预报");
        return AjaxResult.success(planService.list(planQueryWrapper));
    }

    /**
     * 方案删除
     */
    @Transactional
    @DeleteMapping("/plan/del")
    public AjaxResult remove(String id) {
        try {
            // 删除方案数据
            QueryWrapper<XajResult> xajResultQueryWrapper = new QueryWrapper<>();
            xajResultQueryWrapper.eq("plan_id", id);
            xajResultService.remove(xajResultQueryWrapper);
            // 删除方案
            planService.deletePlanById(id);
        } catch (Exception e) {
            return AjaxResult.error("删除失败！");
        }
        return AjaxResult.success("删除成功！");
    }

    /**
     * 方案数据查询
     */
    @GetMapping("/plan/getdata")
    public AjaxResult getData(String id) {
        try {
            Map<Object, Object> map = predictService.getPlanDetail(id);
            return AjaxResult.success(map);
        } catch (Exception e) {
            return AjaxResult.error("数据查询异常！");
        }

    }

    /**
     * 方案对比
     */
    @PostMapping("/plan/contrast")
    public AjaxResult contrast(@RequestBody ContrastDto contrastDto) {
        try {
            Map<Object, Object> map = predictService.contrast(contrastDto);
            return AjaxResult.success(map);
        } catch (Exception e) {
            return AjaxResult.error("数据查询异常！");
        }
    }

    /**
     * 预报手动计算方案保存
     */
    @PostMapping("/plan/save")
    public AjaxResult planSave(@RequestBody PlanDto planDto) {
        try {
            predictService.saveManualPlan(planDto);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return AjaxResult.success("方案保存成功！");
    }

    /**
     * 定时任务预报方案查询
     */
    @GetMapping("/plan/autodata")
    public AjaxResult autoData(String rscd) {
        try {
            Map<Object, Object> map = predictService.getAutoData(rscd);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 定时任务预报方案查询
     */
    @GetMapping("/plan/weatherdata")
    public AjaxResult weatherData(String rscd) {
        try {
            Map<Object, Object> map = predictService.getWeatherData(rscd);
            return AjaxResult.success(map);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 模型参数列表查询
     */
    @GetMapping("/model/paramlist")
    public AjaxResult paramList(ModelParam modelParam) {
        QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
        modelParamQueryWrapper.select("id", "param_num", "param_name", "param_default", "param_min", "param_max", "param_desc")
//                .isNull("plan_id").eq("model_mark", modelParam.getModelMark()).eq("rscd", modelParam.getRscd());
                .isNull("plan_id").eq("model_mark", modelParam.getModelMark()).eq("rscd", "43060030012-A4");
        return AjaxResult.success(modelParamService.list(modelParamQueryWrapper));
    }

    /**
     * 修改模型模型参数
     */
    @PutMapping("/model/paramupdate")
    public AjaxResult paramEdit(@RequestBody ModelParam modelParam) {
        return toAjax(modelParamService.updateModelParam(modelParam));
    }

    /**
     * 模型参数重置为最初值
     */
    @GetMapping("/model/paramreset")
    public AjaxResult paramReset(ModelParam modelParam1) {
        try {
            QueryWrapper<ModelParam> modelParamQueryWrapper = new QueryWrapper<>();
            modelParamQueryWrapper.isNull("plan_id").eq("rscd", modelParam1.getRscd());
            List<ModelParam> list = modelParamService.list(modelParamQueryWrapper);
            // 使用流操作简化代码
            List<ModelParam> updatedList = list.stream()
                    .peek(modelParam -> modelParam.setParamDefault(modelParam.getParamInitial()))
                    .collect(Collectors.toList());
            // 批量更新数据
            if (!updatedList.isEmpty()) {
                modelParamService.updateBatchById(updatedList);
            }
        } catch (Exception e) {
            return AjaxResult.error(e.toString());
        }
        return AjaxResult.success("重置成功！");
    }

    /**
     * 降雨情景列表查询
     */
    @GetMapping("/model/rainsence/list")
    public AjaxResult rainsenceList(RainSence rainSence) {
        try {
            List<RainSence> list = rainSenceService.lambdaQuery()
                    .orderByDesc(RainSence::getCreateTime)
                    .eq(RainSence::getRscd, rainSence.getRscd())
                    .eq(RainSence::getPreType, rainSence.getPreType()).list();
            for (RainSence rainSence2 : list) {
                rainSence2.setDatas(pptnRSenceService.lambdaQuery()
                        .eq(PptnRSence::getSenceId, rainSence2.getId())
                        .orderByAsc(PptnRSence::getTm).list());
            }
            return AjaxResult.success(list);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 保存降雨情景
     *
     * @param rainSenceDto
     * @return
     */
    @PostMapping("/model/rainsence/save")
    public AjaxResult saveRainsence(@RequestBody RainSenceDto rainSenceDto) {
        try {
            predictService.saveRainsence(rainSenceDto);
            return AjaxResult.success("保存成功！");
        } catch (Exception e) {
            throw new RuntimeException(e);

        }
    }

    /**
     * 删除降雨情景
     *
     * @return
     */
    @Transactional
    @DeleteMapping("/rainsence/del")
    public AjaxResult rainsenceDel(String id) {
        try {
            rainSenceService.deleteRainSenceById(id);
            pptnRSenceService.remove(Wrappers.<PptnRSence>lambdaQuery().eq(PptnRSence::getSenceId, id));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return AjaxResult.success("删除成功！");
    }


    /**
     * 获取预报时间
     *
     * @param rscd
     * @return
     */
    @GetMapping("/autodata/getpretm")
    public AjaxResult getPretm(String rscd) {
        try {
            RsvrJob rsvrJob = rsvrJobService.getOne(new LambdaQueryWrapper<RsvrJob>().eq(RsvrJob::getRscd, rscd).eq(RsvrJob::getRemark, "calcTask-calc"));
            return AjaxResult.success(rsvrJob);
        } catch (Exception e) {
            return AjaxResult.error("数据获取异常！");
        }
    }

    /**
     * 修改定时任务时间
     *
     * @param rsvrJob
     * @return
     */
    @PostMapping("/updatersvrjob")
    public AjaxResult updateRsvrJob(@RequestBody RsvrJob rsvrJob) {
        try {
            rsvrJobService.updateById(rsvrJob);
            return AjaxResult.success("修改成功！");
        } catch (Exception e) {
            return AjaxResult.error("修改失败！");
        }
    }


    @GetMapping("/model/setdata")
    public AjaxResult setdata(String stcd) {
        try {
            String startTime = "2023-01-01 00:00:00";
            String endTime = "2024-12-31 23:00:00";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime startDateTime = LocalDateTime.parse(startTime, formatter);
            LocalDateTime endDateTime = LocalDateTime.parse(endTime, formatter);

            List<String> timeList = new ArrayList<>();
            LocalDateTime currentDateTime = startDateTime;
            while (currentDateTime.compareTo(endDateTime) <= 0) {
                timeList.add(currentDateTime.format(formatter));
                currentDateTime = currentDateTime.plusHours(1);
            }
            List<PptnRLaste> pptnRS = new ArrayList<>();
            for (String s : timeList) {
                PptnRLaste pptnR = new PptnRLaste(IdUtils.getId(), stcd, DateUtil.parse(s), Math.random(), 1.0, 0.0, 0.0, "");
//                PptnRLaste pptnR1 = new PptnRLaste(IdUtils.getId(), "61804110", DateUtil.parse(s), Math.random(), 1.0, 0.0, 0.0, "");
//                PptnRLaste pptnR2 = new PptnRLaste(IdUtils.getId(), "61958850", DateUtil.parse(s), Math.random(), 1.0, 0.0, 0.0, "");
                pptnRS.add(pptnR);
//                pptnRS.add(pptnR1);
//                pptnRS.add(pptnR2);
            }
            pptnRLasteService.saveBatch(pptnRS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return AjaxResult.success("操作成功！");

    }

    @GetMapping("/model/setrsvrdata")
    public AjaxResult setdata2(String rscd, Double z) {
        try {
            String startTime = "2023-01-01 00:00:00";
            String endTime = "2024-12-31 23:00:00";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime startDateTime = LocalDateTime.parse(startTime, formatter);
            LocalDateTime endDateTime = LocalDateTime.parse(endTime, formatter);

            List<String> timeList = new ArrayList<>();
            LocalDateTime currentDateTime = startDateTime;
            while (currentDateTime.compareTo(endDateTime) <= 0) {
                timeList.add(currentDateTime.format(formatter));
                currentDateTime = currentDateTime.plusHours(1);
            }
            List<RsvrRLaste> rsvrRS = new ArrayList<>();
            for (String s : timeList) {
                RsvrRLaste rsvrR = new RsvrRLaste(IdUtils.getId(), rscd, DateUtil.parse(s), z + Math.random() * 4, 10 + Math.random() * 10, Math.random() * 50, z + Math.random(), Math.random() * 50, "", "", 0.1, "");

                rsvrRS.add(rsvrR);
            }
            rsvrRLasteService.saveBatch(rsvrRS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return AjaxResult.success("操作成功！");

    }

    /**
     * 导出预报方案简报
     *
     * @param id
     * @return
     * @throws IOException
     */
    @PostMapping("/plan/briefreport")
    public ResponseEntity<byte[]> generateBriefReport(@ModelAttribute DocumentDto documentDto ) throws IOException, InvalidFormatException {
        try {
            QueryWrapper<WrpRsrBsin> wrpRsrBsinQueryWrapper = new QueryWrapper<>();
            wrpRsrBsinQueryWrapper.select("rsnm")
                    .eq("rscd", documentDto.getRscd()).last("limit 1");

            WrpRsrBsin one = wrpRsrBsinService.getOne(wrpRsrBsinQueryWrapper);
            byte[] briefReportDocument = predictService.createBriefReportDocument(documentDto);
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=report.docx");
            headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");

            return new ResponseEntity<>(briefReportDocument, headers, HttpStatus.OK);
        } catch (Exception e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    /**
     * 获取降雨序列
     */
    /**
     * 生成正态分布降雨序列
     */
    @GetMapping("/orthostate")
    public AjaxResult orthostate(@RequestParam(value = "totaldrp") Double totaldrp,
                                 @RequestParam(value = "numt") Integer numt, @RequestParam(value = "type") String type) {
        return predictService.orthostate(totaldrp, numt, type);
    }

}
